package lab2;

import static akka.actor.Actors.poisonPill;
import static akka.actor.Actors.remote;

import java.math.BigInteger;

import akka.actor.ActorRef;
import akka.actor.UntypedActor;

public class Worker extends UntypedActor {
    private static int idGenerator = 0;
    private int actorId;
    private BigInteger n = BigInteger.ZERO; // number to factorize, initialised
                                            // 0 for check on new values
    private BigInteger oldN = BigInteger.ZERO;
    private BigInteger result; // greatest common divisor of (a-b) and n
    private Thread calculator;
    private CalcThread calcor;
    public boolean threadRunning = false;

    public Worker() {
        // Wichtig: Wenn die ID nicht gesetzt wird, wird immer dieselbe In-
        // stanz des Aktors f�r alle Remote-Aufrufe eines Clients verwendet!
        getContext().setId(idGenerator + "");
        actorId = idGenerator;
        System.out.println("Aktor wurde erstellt: " + idGenerator);
        idGenerator++;

    }

    private ActorRef master;

    private void calculate(BigInteger n, BigInteger c) {

        threadRunning = true;
        calcor = new CalcThread(n, c, this);
        calculator = new Thread(calcor);
        calculator.start();
    }//calculate

    public void getResult(BigInteger erg, BigInteger old, BigInteger cycles, long cpuTime) {

        result = erg;

        // System.out.println("\n\n\nErgebnis vom Thread erhalten: " + erg +
        // "\n\n\n");

        ResultMessage resultMessage = new ResultMessage(result, old, cycles, cpuTime);

        // Ergebnis an den Master senden
        master.tell(resultMessage);
        // Durch this.getContext().tell([Nachricht]) kann der Aktor
        // sich selbst eine Nachricht schicken. In diesem Fall schickt
        // sich der Aktor eine "poisonPill". Empf�ngt ein Aktor diese,
        // beendet er sich und postStop() wird aufgerufen.
        if (getContext() != null && getContext().isRunning()) {
            getContext().tell(poisonPill());
        }
    }

    // message handler
    public void onReceive(Object message) {
        if (message instanceof CalculateMessage) {
            // Beim ersten Aufruf wird der Sender ermittel

            CalculateMessage calculateMessage = (CalculateMessage) message;
            this.oldN = this.n;
            this.n = calculateMessage.getA();
         // Alte Berechnung noch am laufen und neuer Wert 
            if (threadRunning && (!this.oldN.equals(this.n))) { 
                calcor.runlock.lock();
                if (calcor.getRunning()) {
                    calcor.terminate();
                    this.master = getContext().getSender().get();
                    calculate(calculateMessage.getA(), calculateMessage.getB());
                }//if
                calcor.runlock.unlock();
            } else if (threadRunning && this.oldN.equals(this.n)) {
                // do nothing, old calculation still valid
            } else { // kein thread am laufen
                this.master = getContext().getSender().get();
                calculate(calculateMessage.getA(), calculateMessage.getB());
            }//else
        } else {
            throw new IllegalArgumentException("Unknown message [" + message + "]");
        }//else
    }//onReceive

    @Override
    public void postStop() {
        System.out.println("Aktor wurde beendet: " + this.actorId);
        super.postStop();
    }//postStop

    public static void main(String[] args) throws Exception {
        remote().start("lab27", 2553);
    }//main
}//Worker